package com.ceair.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ceair.entity.ActReProcdef;
import com.ceair.entity.request.*;
import com.ceair.entity.result.PageResult;
import com.ceair.entity.result.Result;
import com.ceair.entity.vo.ActReProcdefVO;
import com.ceair.entity.vo.DynamicParametersVO;
import com.ceair.service.IActReProcdefService;
import com.ceair.utils.ActReProcdefStructMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * @author wangbaohai
 * @ClassName ActReProcdefController
 * @description: 流程部署定义信息管理相关接口
 * @date 2025年04月21日
 * @version: 1.0.0
 */
@RestController
@RequestMapping("/api/v1/actReProcdef")
@RequiredArgsConstructor
@Slf4j
@Tag(name = "流程部署定义信息管理", description = "流程部署定义信息管理相关接口")
public class ActReProcdefController {

    private final IActReProcdefService actReProcdefService;

    /**
     * 分页查询流程部署定义信息。
     *
     * @param queryActReProcdefReq 流程部署定义信息查询请求对象，包含分页和过滤条件等信息，不能为空。
     * @return 包含流程部署定义信息的分页结果对象，其中数据为视图对象（VO）列表。
     * 如果查询或转换失败，则返回错误信息。
     * <p>
     * 功能描述：
     * 1. 调用服务层方法查询流程部署定义信息，并返回分页结果。
     * 2. 将查询结果中的记录转换为视图对象（VO）列表。
     * 3. 返回包含转换后列表和总记录数的分页结果对象。
     * 4. 捕获并记录查询或转换过程中的异常，返回错误信息。
     */
    @PreAuthorize("hasAnyAuthority('/api/v1/actReProcdef/page')")
    @Parameter(name = "queryActReProcdefReq", description = "流程部署定义信息查询请求对象", required = true)
    @Operation(summary = "分页查询流程部署定义信息")
    @PostMapping("/page")
    public PageResult<List<ActReProcdefVO>> queryActReProcdefWithPage(@RequestBody QueryActReProcdefReq queryActReProcdefReq) {
        try {
            // 调用服务层方法查询流程部署定义信息，并返回分页结果
            Page<ActReProcdef> page = actReProcdefService.queryActReProcdefWithPage(queryActReProcdefReq);

            // 将查询结果中的记录转换为视图对象（VO）列表
            List<ActReProcdefVO> list =
                    Optional.ofNullable(page.getRecords()).orElse(Collections.emptyList()).parallelStream().map(record -> {
                        try {
                            // 使用映射器将实体对象转换为视图对象
                            return ActReProcdefStructMapper.INSTANCE.toVO(record);
                        } catch (Exception e) {
                            // 记录转换失败的错误信息
                            log.error("转换流程部署定义信息失败 具体原因为 : {}", e.getMessage());
                            return null;
                        }
                    }).filter(Objects::nonNull).toList();

            // 返回包含转换后列表和总记录数的分页结果对象
            return PageResult.success(list, page.getTotal());
        } catch (Exception e) {
            // 记录查询失败的错误信息，并返回错误结果
            log.error("查流程部署定义信息失败 具体原因为 : {}", e.getMessage());
            return PageResult.error("查询流程部署定义信息失败：" + e.getMessage());
        }
    }

    /**
     * 操作流程定义(激活/挂起)。
     * <p>
     * 该方法通过调用服务层的 `operateProcessDefinitionById` 方法，根据请求对象中的信息对流程定义进行操作（如激活或挂起）。
     * 如果操作成功，则返回成功的响应结果；如果发生异常，则记录错误日志并返回失败的响应结果。
     *
     * @param operateActReProcdefReq 流程定义操作请求对象，包含操作所需的参数信息，不能为空。
     *                               该对象通过 HTTP 请求体传递，需符合 `OperateActReProcdefReq` 的结构定义。
     * @return 返回一个 `Result<Boolean>` 对象：
     * - 如果操作成功，返回 `Result.success(true)`；
     * - 如果操作失败，返回 `Result.error`，并包含失败原因的描述信息。
     */
    @PreAuthorize("hasAnyAuthority('/api/v1/actReProcdef/operate')")
    @Parameter(name = "operateActReProcdefReq", description = "流程定义操作请求对象", required = true)
    @Operation(summary = "操作流程定义(激活/挂起)")
    @PostMapping("/operate")
    public Result<Boolean> operateProcessDefinitionById(@RequestBody OperateActReProcdefReq operateActReProcdefReq) {
        try {
            // 调用服务层方法执行流程定义操作，传入请求对象并获取操作结果
            Boolean operateResult = actReProcdefService.operateProcessDefinitionById(operateActReProcdefReq);

            // 返回操作成功的响应结果
            return Result.success(operateResult);
        } catch (Exception e) {
            // 捕获异常，记录详细的错误日志，并返回包含失败原因的响应结果
            log.error("操作流程定义失败 具体原因为 : {}", e.getMessage());
            return Result.error("操作流程定义失败,失败原因：" + e.getMessage());
        }
    }

    // 使用Spring Security的注解进行权限控制，确保只有拥有特定权限的用户才能访问此方法
    @PreAuthorize("hasAnyAuthority('/api/v1/actReProcdef/queryImage')")
    // 定义参数对象的元数据，用于API文档生成
    @Parameter(name = "queryImageOrXmlReq", description = "查询流程定义图片请求对象", required = true)
    // 定义操作的元数据，用于API文档生成
    @Operation(summary = "查询流程定义图片")
    // 声明这是一个POST请求的处理方法
    @PostMapping("/queryImage")
    public Result<String> queryImage(@RequestBody QueryImageOrXmlReq queryImageOrXmlReq) {
        try {
            // 调用服务层方法执行流程定义操作，传入请求对象并获取操作结果bpmnModel = {BpmnModel@18299}
            String image = actReProcdefService.queryImage(queryImageOrXmlReq);

            // 返回操作成功的响应结果
            return Result.success(image);
        } catch (Exception e) {
            // 捕获异常，记录详细的错误日志，并返回包含失败原因的响应结果
            log.error("查询流程定义图片失败 具体原因为 : {}", e.getMessage());
            return Result.error("查询流程定义图片失败,失败原因：" + e.getMessage());
        }
    }

    // 使用Spring Security的注解进行权限控制，只有拥有特定权限的用户才能访问此方法
    @PreAuthorize("hasAnyAuthority('/api/v1/actReProcdef/queryXml')")
    // 定义参数对象的元数据，用于API文档生成
    @Parameter(name = "queryImageOrXmlReq", description = "查询流程定义图片请求对象", required = true)
    // 定义操作的元数据，用于API文档生成
    @Operation(summary = "查询流程定义XML")
    // 声明这是一个POST类型的HTTP请求处理方法
    @PostMapping("/queryXml")
    public Result<String> queryXML(@RequestBody QueryImageOrXmlReq queryImageOrXmlReq) {
        try {
            // 调用服务层方法执行流程定义操作，传入请求对象并获取操作结果
            String xml = actReProcdefService.queryXML(queryImageOrXmlReq);

            // 返回操作成功的响应结果
            return Result.success(xml);
        } catch (Exception e) {
            // 捕获异常，记录详细的错误日志，并返回包含失败原因的响应结果
            log.error("查询流程定义XML失败 具体原因为 : {}", e.getMessage());
            return Result.error("查询流程定义XML失败,失败原因：" + e.getMessage());
        }
    }

    /**
     * 查询流程定义的动态参数
     * <p>
     * 此方法接收一个QueryDynamicParametersReq对象作为请求体，用于指定查询条件
     * 使用Spring Security的注解进行权限控制，只有拥有特定权限的用户才能访问此方法
     * 它调用actReProcdefService的queryDynamicParameters方法来获取动态参数列表
     * 如果调用成功，返回包含DynamicParametersVO列表的Result对象
     * 如果调用失败，返回一个错误的Result对象，包含错误信息
     *
     * @param queryDynamicParametersReq 查询流程动态参数的请求对象
     * @return 包含动态参数列表的Result对象，或包含错误信息的Result对象
     */
    @PreAuthorize("hasAnyAuthority('/api/v1/actReProcdef/queryDynamicParameters')")
    @Parameter(name = "queryDynamicParametersReq", description = "查询不俗流程动态参数", required = true)
    @Operation(summary = "查询流程定义动态参数")
    @PostMapping("/queryDynamicParameters")
    public Result<List<DynamicParametersVO>> queryDynamicParameters(@RequestBody QueryDynamicParametersReq
                                                                                queryDynamicParametersReq) {
        try {
            // 调用服务层方法查询动态参数
            return Result.success(actReProcdefService.queryDynamicParameters(queryDynamicParametersReq));
        } catch (Exception e) {
            // 记录查询失败的日志
            log.error("查询流程定义动态参数失败 具体原因为 : {}", e.getMessage());
            // 返回查询失败的错误信息
            return Result.error("查询流程定义动态参数失败,失败原因：" + e.getMessage());
        }
    }

    /**
     * 启动流程定义。
     * <p>
     * 功能描述：
     * 1. 使用Spring Security的注解进行权限控制，确保只有拥有`/api/v1/actReProcdef/startProcess`权限的用户才能访问此方法。
     * 2. 接收一个`StartProcessReq`对象作为请求体，表示启动流程所需的参数。
     * 3. 调用服务层`actReProcdefService.startProcess`方法执行流程启动操作，并返回操作结果。
     * 4. 如果操作成功，返回包含`true`的`Result<Boolean>`对象；如果发生异常，记录错误日志并返回包含失败原因的错误响应。
     *
     * @param startProcessReq 启动流程请求对象，包含启动流程所需的所有参数，不能为空。
     * @return 返回一个`Result<Boolean>`对象：
     * - 如果启动成功，返回`Result.success(true)`；
     * - 如果启动失败，返回`Result.error`，并包含失败原因的描述信息。
     */
    @PreAuthorize("hasAnyAuthority('/api/v1/actReProcdef/startProcess')")
    @Parameter(name = "startProcessReq", description = "启动流程请求对象", required = true)
    @Operation(summary = "启动流程")
    @PostMapping("/startProcess")
    public Result<Boolean> startProcess(@RequestBody StartProcessReq startProcessReq) {
        try {
            Boolean operateResult = actReProcdefService.startProcess(startProcessReq);
            return Result.success(operateResult);
        } catch (Exception e) {
            log.error("启动流程失败 具体原因为 : {}", e.getMessage());
            return Result.error("启动流程失败,失败原因：" + e.getMessage());
        }
    }


}
